package main

import (
	"context"
	"errors"
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"gitee.com/zawei/yggdrasil/pkg/lib/omega"
	"gitee.com/zawei/yggdrasil/pkg/log"
)

var (
	lock                            = sync.Mutex{}
	BALANCES                        map[string]int
	TransferMoneySagaStartDecorated func(ctx context.Context, i int) error
	TransferOutCompensableDecorated func(ctx context.Context, i int, from string, amount int) error
	TransferInCompensableDecorated  func(ctx context.Context, i int, to string, amount int) error
	TransferIn2CompensableDecorated func(ctx context.Context, i int, to string, amount int) error
	TransferMoneySagaEndDecorated   func(ctx context.Context) error
)

func init() {
	err := omega.DecorateSagaMethod(&TransferMoneySagaStartDecorated, TransferMoney, 10, true)
	if err != nil {
		panic(err)
	}
	err = omega.DecorateTxMethod(&TransferOutCompensableDecorated, TransferOut, CancelTransferOut, 5)
	if err != nil {
		panic(err)
	}
	err = omega.DecorateTxMethod(&TransferInCompensableDecorated, TransferIn, CancelTransferIn, 5)
	if err != nil {
		panic(err)
	}
	err = omega.DecorateTxMethod(&TransferIn2CompensableDecorated, TransferIn2, CancelTransferIn2, 5)
	if err != nil {
		panic(err)
	}
	err = omega.DecorateSagaEndMethod(&TransferMoneySagaEndDecorated, TransferMoneyEnd)
	if err != nil {
		panic(err)
	}
	initDatas()
}

func initDatas() {
	BALANCES = make(map[string]int, 0)
	BALANCES["foo"] = 500
	BALANCES["bar"] = 500
}

func TransferMoneyEnd(ctx context.Context) error {
	return nil
}

func TransferMoney(ctx context.Context, i int) error {
	fmt.Print("TransferMoney ", " ")
	fmt.Println(omega.GetAllFromContext(ctx))
	defer func() {
		fmt.Print("TransferMoney ", i, " ")
		fmt.Println(omega.GetAllFromContext(ctx))
	}()
	err := TransferOutCompensableDecorated(ctx, i, "foo", 100)
	if err != nil {
		return err
	}
	err = TransferInCompensableDecorated(ctx, i, "bar", 100)
	if err != nil {
		return err
	}
	err = TransferIn2CompensableDecorated(ctx, i, "bar", 100)
	if err != nil {
		return err
	}
	return nil
}

func TransferOut(ctx context.Context, i int, from string, amount int) error {
	fmt.Print("TransferOut ")
	fmt.Println(omega.GetAllFromContext(ctx))
	defer func() {
		fmt.Print("TransferOut ", i, " ")
		fmt.Println(omega.GetAllFromContext(ctx))
	}()
	lock.Lock()
	defer lock.Unlock()

	oldAmount, _ := BALANCES[from]
	if oldAmount < amount {
		return errors.New("balance fff")
	}
	BALANCES[from] = oldAmount - amount
	return nil
}

func CancelTransferOut(ctx context.Context, i int, from string, amount int) error {
	fmt.Print("CancelTransferOut ")
	fmt.Println(omega.GetAllFromContext(ctx))
	lock.Lock()
	defer lock.Unlock()

	oldAmount, _ := BALANCES[from]
	BALANCES[from] = oldAmount + amount
	return nil //
}

func TransferIn(ctx context.Context, i int, to string, amount int) error {
	fmt.Print("TransferIn ")
	fmt.Println(omega.GetAllFromContext(ctx))
	defer func() {
		fmt.Print("TransferIn ", i, " ")
		fmt.Println(omega.GetAllFromContext(ctx))
	}()
	oldAmount, _ := BALANCES[to]
	BALANCES[to] = oldAmount + amount
	return nil
}

func CancelTransferIn(ctx context.Context, i int, to string, amount int) error {
	fmt.Print("CancelTransferIn ")
	fmt.Println(omega.GetAllFromContext(ctx))
	lock.Lock()
	defer lock.Unlock()
	oldAmount, _ := BALANCES[to]
	BALANCES[to] = oldAmount - amount
	return nil
}

func TransferIn2(ctx context.Context, i int, to string, amount int) error {
	fmt.Print("TransferIn2 ")
	fmt.Println(omega.GetAllFromContext(ctx))
	defer func() {
		fmt.Print("TransferIn2 ", i, " ")
		fmt.Println(omega.GetAllFromContext(ctx))
	}()

	oldAmount, _ := BALANCES[to]
	BALANCES[to] = oldAmount + amount
	return nil

}

func CancelTransferIn2(ctx context.Context, i int, to string, amount int) error {
	fmt.Print("CancelTransferIn2 ")
	fmt.Println(omega.GetAllFromContext(ctx))
	lock.Lock()
	defer lock.Unlock()
	oldAmount, _ := BALANCES[to]
	BALANCES[to] = oldAmount - amount
	return nil
}

func main() {
	cfg := &omega.Config{
		Transport: omega.TransportConfig{
			ServiceName: "omega",
			InstanceId:  "omega-123456",
			GrcpClient:  omega.GrpcClientConfig{Target: "localhost:18080"},
		},
		AkkaEnabled: true,
	}
	cfg.WithLogger((&zap.Config{Level: "debug"}).Build())
	// 这里的第一个参数是本服务的名称，第二个参数是alpha-server的地址，第三个参数是Logger
	if err := omega.InitOmega(context.Background(), cfg); err != nil {
		panic(err)
	}
	fmt.Printf("foo balance: %d, bar balance: %d\n", BALANCES["foo"], BALANCES["bar"])
	stopped := false
	if err := TransferMoneySagaStartDecorated(context.TODO(), 0); err != nil {
		fmt.Println(err.Error())
	}

	fmt.Printf("foo balance: %d, bar balance: %d\n", BALANCES["foo"], BALANCES["bar"])

	go func() {
		s := make(chan os.Signal)
		signal.Notify(s, syscall.SIGINT, syscall.SIGTERM)
		<-s
		omega.CloseOmega()
		stopped = true
	}()
	for !stopped {
		fmt.Printf("222 foo balance: %d, bar balance: %d\n", BALANCES["foo"], BALANCES["bar"])
		time.Sleep(time.Second * 3)
	}
}
